from django.test import TestCase
from django.utils import timezone
from api.models import User, Role, RelationUserRole
from api.views.auth_management.views import get_user_level
from datetime import datetime
import time
from Crypto.Cipher import AES
import base64


def create_user(username, password):
    user = User.objects.create(
        username=username,
        password=password,
        phone="",
        email="",
        department="系统管理",
        description="",
        create_time=timezone.now(),
        last_edit_time=timezone.now(),
    )
    return user.id


def create_role(level, code):
    role = Role.objects.create(
        level=level,
        name="test",
        code=code,
        description="管理员",
        create_time=timezone.now(),
        last_edit_time=timezone.now(),
        fault_injection=True,
        data_monitor=True,
        detection=True,
        diagnosis=True,
        manage=True,
        RecordShow=True,
    )
    return role.id


def get_token(client, username, password):
    response = client.post(
        "/login", {"username": username, "password": password}, "application/json"
    )
    return response.json()["data"]["token"]


class TestAuthManagement(TestCase):
    def __init__(self, methodName: str = "runTest") -> None:
        super().__init__(methodName)

    def test_get_user_level(self):
        # role_ids = []
        id = create_user("aiops@admin", "nkcs@aiops")
        level = get_user_level(id)
        self.assertEqual(level, 0x7FFFFFFF)

        # role_ids = [...]
        r_id = create_role(1, "admin")
        rr_id = create_role(2, "user")
        create_role(3, "test1")
        RelationUserRole.objects.create(user_id=id, role_id=r_id)
        RelationUserRole.objects.create(user_id=id, role_id=rr_id)
        level = get_user_level(id)
        self.assertEqual(level, 1)

    def test_role_query(self):
        url = "/role/query"
        id = create_user("aiops@admin", "nkcs@aiops")
        token = get_token(self.client, "aiops@admin", "nkcs@aiops")
        # roles = []
        response = self.client.get(url, HTTP_AUTHORIZATION=f"token {token}")
        self.assertIsInstance(response.json()["data"], list)
        # roles = [...]
        r_id = create_role(1, "admin")
        RelationUserRole.objects.create(user_id=id, role_id=r_id)
        create_role(2, "user")
        create_role(3, "test1")
        create_role(4, "test2")
        response = self.client.get(url, HTTP_AUTHORIZATION=f"token {token}")
        self.assertEqual(4, len(response.json()["data"]))

    def test_role_add(self):
        url = "/role/add"
        fake_data = {
            "level": -1,
            "name": "?",
            "code": "?",
            "desc": "?",
            "createTime": int(time.time() * 1000),
            "lastEditTime": int(time.time() * 1000),
            "authorityListDict": {
                "Fault-injection": True,
                "DataMonitor": True,
                "Detection": True,
                "Diagnosis": True,
                "Manage": True,
                "RecordShow": True,
            },
        }
        id = create_user("aiops@admin", "nkcs@aiops")
        token = get_token(self.client, "aiops@admin", "nkcs@aiops")
        # no role
        response = self.client.post(
            url,
            data=fake_data,
            HTTP_AUTHORIZATION=f"token {token}",
            content_type="application/json",
        )
        self.assertEqual("Not permitted to add role!", response.json()["message"])
        # not exist, create
        r_id = create_role(1, "admin")
        RelationUserRole.objects.create(user_id=id, role_id=r_id)
        response = self.client.post(
            url,
            data=fake_data,
            HTTP_AUTHORIZATION=f"token {token}",
            content_type="application/json",
        )
        self.assertEqual(200, response.status_code)
        # already exist, rt
        response = self.client.post(
            url,
            data=fake_data,
            HTTP_AUTHORIZATION=f"token {token}",
            content_type="application/json",
        )
        self.assertEqual("Role Already Exists!", response.json()["message"])

    def test_role_modify(self):
        url = "/role/modify"
        fake_data = {
            "level": -1,
            "name": "?",
            "code": "?",
            "desc": "?",
            "createTime": int(time.time() * 1000),
            "lastEditTime": int(time.time() * 1000),
            "authorityListDict": {
                "Fault-injection": True,
                "DataMonitor": True,
                "Detection": True,
                "Diagnosis": True,
                "Manage": True,
                "RecordShow": True,
            },
        }
        id = create_user("aiops@admin", "nkcs@aiops")
        token = get_token(self.client, "aiops@admin", "nkcs@aiops")
        # not exists
        response = self.client.put(
            url,
            data=fake_data,
            HTTP_AUTHORIZATION=f"token {token}",
            content_type="application/json",
        )
        self.assertEqual("Role Not Exists!", response.json()["message"])
        # exists
        create_role(1, "?")
        response = self.client.put(
            url,
            data=fake_data,
            HTTP_AUTHORIZATION=f"token {token}",
            content_type="application/json",
        )
        self.assertEqual(200, response.status_code)

    def test_role_delete(self):
        url = "/role/delete"
        fake_data = {
            "level": -1,
            "name": "?",
            "code": "?",
            "desc": "?",
            "createTime": int(time.time() * 1000),
            "lastEditTime": int(time.time() * 1000),
            "authorityListDict": {
                "Fault-injection": True,
                "DataMonitor": True,
                "Detection": True,
                "Diagnosis": True,
                "Manage": True,
                "RecordShow": True,
            },
        }
        id = create_user("aiops@admin", "nkcs@aiops")
        token = get_token(self.client, "aiops@admin", "nkcs@aiops")
        # not exists
        response = self.client.delete(
            url,
            data=fake_data,
            HTTP_AUTHORIZATION=f"token {token}",
            content_type="application/json",
        )
        self.assertEqual("Role Not Exists!", response.json()["message"])
        # exists
        create_role(1, "?")
        response = self.client.delete(
            url,
            data=fake_data,
            HTTP_AUTHORIZATION=f"token {token}",
            content_type="application/json",
        )
        self.assertEqual(200, response.status_code)

    def test_role_queryauth(self):
        url = "/role/queryauth"
        id = create_user("aiops@admin", "nkcs@aiops")
        token = get_token(self.client, "aiops@admin", "nkcs@aiops")
        # roles = []
        response = self.client.get(url, HTTP_AUTHORIZATION=f"token {token}")
        self.assertEqual(0, len(response.json()["data"]))
        # roles = [...]
        r_id = create_role(1, "admin")
        RelationUserRole.objects.create(user_id=id, role_id=r_id)
        r_id = create_role(2, "user")
        RelationUserRole.objects.create(user_id=id, role_id=r_id)
        r_id = create_role(3, "test1")
        RelationUserRole.objects.create(user_id=id, role_id=r_id)
        r_id = create_role(4, "test2")
        RelationUserRole.objects.create(user_id=id, role_id=r_id)
        response = self.client.get(url, HTTP_AUTHORIZATION=f"token {token}")
        self.assertEqual(3, len(response.json()["data"]))

    def test_user_query(self):
        url = "/user/query"
        id = create_user("aiops@admin", "nkcs@aiops")
        token = get_token(self.client, "aiops@admin", "nkcs@aiops")
        ur_id = create_role(2, "user")
        RelationUserRole.objects.create(user_id=id, role_id=ur_id)

        # user = [], new_user = []
        response = self.client.get(url, HTTP_AUTHORIZATION=f"token {token}")
        self.assertEqual(0, len(response.json()["data"]))
        # user = [...], new_user = []
        ar_id = create_role(1, "admin")
        t1 = create_user("t1", "t1")
        t2 = create_user("t2", "t2")
        RelationUserRole.objects.create(user_id=t1, role_id=ar_id)
        RelationUserRole.objects.create(user_id=t2, role_id=ar_id)
        response = self.client.get(url, HTTP_AUTHORIZATION=f"token {token}")
        self.assertEqual(0, len(response.json()["data"]))
        # user = [...], new_user = [...], role_ids = [](all)
        lower_id = create_role(3, "lower")
        t3 = create_user("t3", "t3")
        t4 = create_user("t4", "t4")
        response = self.client.get(url, HTTP_AUTHORIZATION=f"token {token}")
        self.assertEqual(2, len(response.json()["data"]))
        # user = [...], new_user = [...], role_ids = [...](all)
        RelationUserRole.objects.create(user_id=t3, role_id=lower_id)
        RelationUserRole.objects.create(user_id=t4, role_id=lower_id)
        response = self.client.get(url, HTTP_AUTHORIZATION=f"token {token}")
        self.assertEqual(2, len(response.json()["data"]))

    def test_user_add(self):
        url = "/user/add"
        encoder = AES.new(b"nkcs@@@@aiops@!3", mode=AES.MODE_ECB)
        password = b"1231111111111111"
        fake_data = {
            "id": 0,
            "name": "张三",
            "phone": "13478414545",
            "email": "",
            "password": base64.b64encode(encoder.encrypt(password)).decode(),
            "department": "管理部门",
            "createTime": int(time.time() * 1000),
            "lastEditTime": int(time.time() * 1000),
            "description": "",
            "ownRoles": ["user"],
        }
        id = create_user("aiops@admin", "nkcs@aiops")
        token = get_token(self.client, "aiops@admin", "nkcs@aiops")
        # name = "aiops@admin" # exists
        fake_data["name"] = "aiops@admin"
        response = self.client.post(
            url,
            data=fake_data,
            HTTP_AUTHORIZATION=f"token {token}",
            content_type="application/json",
        )
        self.assertEqual("Username Already Exists", response.json()["message"])
        # ownRoles = []
        fake_data["name"] = "test1"
        fake_data["ownRoles"] = []
        response = self.client.post(
            url,
            data=fake_data,
            HTTP_AUTHORIZATION=f"token {token}",
            content_type="application/json",
        )
        self.assertEqual(200, response.status_code)
        # ownRoles = ["admin"]
        fake_data["name"] = "test2"
        fake_data["ownRoles"] = ["admin"]
        response = self.client.post(
            url,
            data=fake_data,
            HTTP_AUTHORIZATION=f"token {token}",
            content_type="application/json",
        )
        self.assertEqual(200, response.status_code)
        # ownRoles = ["fake??"]
        fake_data["name"] = "test3"
        fake_data["ownRoles"] = ["fake"]
        response = self.client.post(
            url,
            data=fake_data,
            HTTP_AUTHORIZATION=f"token {token}",
            content_type="application/json",
        )
        self.assertEqual(200, response.status_code)

    def test_user_delete(self):
        url = "/user/delete"
        id = create_user("aiops@admin", "nkcs@aiops")
        token = get_token(self.client, "aiops@admin", "nkcs@aiops")
        # not exists
        response = self.client.delete(
            url,
            data={"id": 0000},
            HTTP_AUTHORIZATION=f"token {token}",
            content_type="application/json",
        )
        self.assertEqual("User Not Exists!", response.json()["message"])
        # exists
        del_id = create_user("test", "test")
        response = self.client.delete(
            url,
            data={"id": del_id},
            HTTP_AUTHORIZATION=f"token {token}",
            content_type="application/json",
        )
        self.assertEqual(200, response.status_code)

    def test_user_modify(self):
        url = "/user/modify"
        encoder = AES.new(b"nkcs@@@@aiops@!3", mode=AES.MODE_ECB)
        password = b"1231111111111111"
        fake_data = {
            "id": 0,
            "name": "张三",
            "phone": "13478414545",
            "email": "",
            "password": base64.b64encode(encoder.encrypt(password)).decode(),
            "department": "管理部门",
            "createTime": int(time.time() * 1000),
            "lastEditTime": int(time.time() * 1000),
            "description": "",
            "ownRoles": ["user"],
        }
        id = create_user("aiops@admin", "nkcs@aiops")
        token = get_token(self.client, "aiops@admin", "nkcs@aiops")
        # password == "", id not valid, []
        fake_data["password"] = ""
        fake_data["id"] = -1
        fake_data["ownRoles"] = []
        response = self.client.put(
            url,
            data=fake_data,
            HTTP_AUTHORIZATION=f"token {token}",
            content_type="application/json",
        )
        self.assertEqual("User Doesn't Exist", response.json()["message"])
        # password != "", password!=data["password"], id valid, ["???"]
        fake_data["password"] = base64.b64encode(encoder.encrypt(password)).decode()
        fake_data["id"] = id
        fake_data["ownRoles"] = ["???"]
        response = self.client.put(
            url,
            data=fake_data,
            HTTP_AUTHORIZATION=f"token {token}",
            content_type="application/json",
        )
        self.assertEqual(200, response.status_code)
        # password != "", password==data["password"], id valid, ["admin"]
        create_role(1, "admin")
        fake_data["password"] = base64.b64encode(
            encoder.encrypt(User.objects.get(id=id).password.encode())
        ).decode()
        fake_data["id"] = id
        fake_data["ownRoles"] = ["admin"]
        response = self.client.put(
            url,
            data=fake_data,
            HTTP_AUTHORIZATION=f"token {token}",
            content_type="application/json",
        )
        self.assertEqual(200, response.status_code)
        # password == "", id valid, []
        fake_data["password"] = ""
        fake_data["id"] = id
        fake_data["ownRoles"] = []
        response = self.client.put(
            url,
            data=fake_data,
            HTTP_AUTHORIZATION=f"token {token}",
            content_type="application/json",
        )
        self.assertEqual(200, response.status_code)

    def test_user_deletebatch(self):
        url = "/user/deletebatch"
        id = create_user("aiops@admin", "nkcs@aiops")
        token = get_token(self.client, "aiops@admin", "nkcs@aiops")
        # data []
        response = self.client.delete(
            url,
            data=[],
            HTTP_AUTHORIZATION=f"token {token}",
            content_type="application/json",
        )
        self.assertEqual(200, response.status_code)
        # data [9999] invalid
        response = self.client.delete(
            url,
            data=[9999],
            HTTP_AUTHORIZATION=f"token {token}",
            content_type="application/json",
        )
        self.assertEqual("User Not Exists!", response.json()["message"])

        # data [1, 2] valid
        t1 = create_user("test1", "test1")
        t2 = create_user("test2", "test2")
        response = self.client.delete(
            url,
            data=[t1, t2],
            HTTP_AUTHORIZATION=f"token {token}",
            content_type="application/json",
        )
        self.assertEqual(200, response.status_code)

    def test_user_queryauthority(self):
        url = "/user/queryauthority"
        id = create_user("aiops@admin", "nkcs@aiops")
        token = get_token(self.client, "aiops@admin", "nkcs@aiops")
        # role_ids = []
        response = self.client.get(url, HTTP_AUTHORIZATION=f"token {token}")
        self.assertEqual(200, response.status_code)
        # role_ids = [...], and {authorityListDict all true}
        r_id = create_role(1, "admin")
        RelationUserRole.objects.create(user_id=id, role_id=r_id)
        response = self.client.get(url, HTTP_AUTHORIZATION=f"token {token}")
        for val in response.json()["data"].values():
            self.assertEqual(True, val)
        # role_ids = [...], and {authorityListDict all false}
        r = Role.objects.get(id=r_id)
        r.fault_injection = False
        r.data_monitor = False
        r.detection = False
        r.diagnosis = False
        r.manage = False
        r.RecordShow = False
        r.save()
        response = self.client.get(url, HTTP_AUTHORIZATION=f"token {token}")
        for val in response.json()["data"].values():
            self.assertEqual(False, val)
